Skip to content

Add experimentalForceOwningTab for Web Worker support #2197

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 33 commits into from
Jun 1, 2020

Conversation

thebrianchen
Copy link

@thebrianchen thebrianchen commented Sep 26, 2019

Original issue: #983
Provides an experimental feature to support offline persistence in web workers.

I've updated the sample app with the latest changes as well (link).

There also seem to be some changes from running prettier that probably weren't pushed in other commits.

Copy link
Contributor

@mikelehen mikelehen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly LGTM but I left a few nits and I think we need to refine when force can override canActAsPrimary...

* Whether to force enable persistence for the client. This cannot be used
* with `synchronizeTabs:true` and is primarily intended for use with Web
* Workers. Setting this to 'true' will enable persistence, but cause other
* tabs using persistence to fail.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: If/when we ship this for real we should add more detail about exactly how other tabs will fail (so that developers can potentially write code to detect it, etc.).

if (indexedDB !== undefined) {
request = indexedDB.open(name, version);
} else {
request = window.indexedDB.open(name, version);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since window is usually the global object and we've already checked for the indexedDB global directly, is there a case where we will ever hit this?

Maybe we have a fake window object in node tests or something? Do you know?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I demand answers too :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looked into this some more and since window is bound to globalThis in the dom, we won't ever hit this line unless window has been mocked out and the indexedDB global doesn't exist.

Deleted.

// If IndexedDb is available directly (ex: in case of web workers).
if (typeof indexedDB !== 'undefined') {
return true;
}
if (typeof window === 'undefined' || window.indexedDB == null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per above, since window is usually the global object and we've already checked for the indexedDB global directly, is there a case where we will ever hit this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still need this for cases where indexedDB and window aren't available and return false, or else an environment without a global indexedDB that passes the other checks will incorrectly return true for isAvailable().

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we just need to register the IndexedDb shim directly on globalAny in node_persistence.ts.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added comment for why it's already registered.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't that mean that "if (typeof window === 'undefined' || window.indexedDB == null)" is now no longer needed? Is your distinction from your first response here still relevant? if so, we should probably talk this through offline.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per offline conversation, removed the window logic, and flipped the indexedDB check to return false. By returning true automatically when IndexedDB is available, we are skipping all of the UA checks.

Also removed the window.navigator check, to make sure workers aren't rejected early.

@mikelehen mikelehen assigned thebrianchen and unassigned mikelehen Sep 27, 2019
Copy link
Contributor

@mikelehen mikelehen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good for the purpose of gathering feedback!

@mikelehen mikelehen assigned thebrianchen and unassigned mikelehen Oct 1, 2019
Copy link
Author

@thebrianchen thebrianchen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for sticking through with me on this :)

return withPersistence('clientA', async db => {
await withForcedPersistence('clientB', async () => {
return expect(
db.runTransaction('tx', 'readwrite-primary', () =>
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

@@ -1005,11 +1024,12 @@ export class IndexedDbPersistence implements Persistence {

private detachWindowUnloadHook(): void {
if (this.windowUnloadHandler) {
assert(this.window != null, "'window' should be defined");
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't realized we've separated out asserts. thanks

@@ -239,7 +242,8 @@ export class IndexedDbPersistence implements Persistence {
lruParams: LruParams,
private readonly queue: AsyncQueue,
serializer: JsonProtoSerializer,
private readonly sequenceNumberSyncer: SequenceNumberSyncer
private readonly sequenceNumberSyncer: SequenceNumberSyncer,
private readonly forceOwningTab: boolean
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

@@ -587,6 +602,9 @@ export class IndexedDbPersistence implements Persistence {
}

if (!this.isLocalClient(currentPrimary)) {
if (this.forceOwningTab) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are already using the forceOwningTab logic in updateClientMetadataAndTryBecomePrimary, we don't need the check here anymore. Removed.

// If IndexedDb is available directly (ex: in case of web workers).
if (typeof indexedDB !== 'undefined') {
return true;
}
if (typeof window === 'undefined' || window.indexedDB == null) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per offline conversation, removed the window logic, and flipped the indexedDB check to return false. By returning true automatically when IndexedDB is available, we are skipping all of the UA checks.

Also removed the window.navigator check, to make sure workers aren't rejected early.

'IndexedDB persistence is only available on platforms that support LocalStorage.'
);
this.webStorage = null;
if (forceOwningTab === false) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We now throw an error if synchronizeTabs is used with experimentalForceOwningTab, and we throw an error if LocalStorage is unavailable in WebStorageSharedClientState. Which case are we not covering?

Copy link
Contributor

@schmidt-sebastian schmidt-sebastian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@@ -585,6 +585,9 @@ export class IndexedDbPersistence implements Persistence {
private canActAsPrimary(
txn: PersistenceTransaction
): PersistencePromise<boolean> {
if (this.forceOwningTab) {
return PersistencePromise.resolve<boolean>(true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can probably drop the generic since it can be inferred.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why TS can't infer it, but the error I get is:
Type 'PersistencePromise<true>' is not assignable to type 'PersistencePromise<boolean>'.

Copy link
Contributor

@egilmorez egilmorez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All language in index.d.ts LGTM with a tiny nit. Thanks!

/**
* Whether to force enable persistence for the client. This cannot be used
* with `synchronizeTabs:true` and is primarily intended for use with Web
* Workers. Setting this to 'true' will enable persistence, but cause other
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was the intention to use backticks around true ? That would work.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

@thebrianchen thebrianchen assigned Feiyang1 and unassigned egilmorez Jun 1, 2020
@@ -0,0 +1,9 @@
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean to commit this file?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for catching

@thebrianchen thebrianchen merged commit 5547861 into master Jun 1, 2020
@thebrianchen thebrianchen deleted the bc/ww-persist branch June 1, 2020 23:52
@firebase firebase locked and limited conversation to collaborators Jul 2, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants